﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WindowsFormsApp1.IICMoudle
{
    class ChipMaxim : IChip
    {
        private static readonly int REWRITE_TIMES = I2CConstant.REWRITE_TIMES;

        private byte curMode;

        public IICDataListener Listener { get; set; }

        public bool WriteReg(byte[] writeData, int writeLen)
        {
            byte[] wBuf = new byte[256];
            byte[] rBuf = new byte[256];
            uint wLen;
            uint rLen;

            wBuf[0] = I2CConstant.REG_IIC_ADDRESS;

            for (int i = 1; i <= writeLen; i++)
            {
                wBuf[i] = writeData[i - 1];
            }
            wLen = (uint)(writeLen + 1);
            rLen = 0;
            return IIC.WriteRead(wLen, wBuf, rLen, rBuf);
        }

        public byte[] ReadReg(byte[] readData, int readLen)
        {
            byte[] wBuf = new byte[256];
            byte[] rBuf = new byte[256];
            uint wLen;
            uint rLen;

            wBuf[0] = I2CConstant.REG_IIC_ADDRESS;

            for (int i = 1; i <= readData.Length; i++)
            {
                wBuf[i] = readData[i - 1];
            }
            wLen = (uint)(readData.Length + 1);
            rLen = (uint)readLen;
            IIC.WriteRead(wLen, wBuf, rLen, rBuf);

            byte[] result = new byte[readLen];
            Array.Copy(rBuf, 0, result, 0, readLen);

            return result;
        }

        public void SetDebugMode(byte mode)
        {
            this.curMode = mode;

            byte[] wBuf = new byte[256];
            byte[] rBuf = new byte[256];

            wBuf[0] = I2CConstant.REG_IIC_ADDRESS;
            wBuf[1] = (byte)ChipMaximConstance.Reg.REG_DEBUG_MODE_A;
            wBuf[2] = mode;
            IIC.WriteRead(3, wBuf, 0, rBuf);
        }

        public void ClearDataReady()
        {
            byte[] wBuf = new byte[256];
            byte[] rBuf = new byte[256];

            wBuf[0] = I2CConstant.REG_IIC_ADDRESS;
            wBuf[1] = (byte)ChipMaximConstance.Reg.REG_DATA_READY_A;
            wBuf[2] = (byte)ChipMaximConstance.DataReady.DATA_READY_CLEAR;
            IIC.WriteRead(3, wBuf, 0, rBuf);
        }

        public int ReadDataReady()
        {
            byte[] wBuf = new byte[256];
            byte[] rBuf = new byte[256];

            wBuf[0] = I2CConstant.REG_IIC_ADDRESS;
            wBuf[1] = (byte)ChipMaximConstance.Reg.REG_DATA_READY_A;

            if (IIC.WriteRead(2, wBuf, 1, rBuf))
            {
                return rBuf[0];
            }
            else
            {
                return -1;
            }
        }

        public int[] GetData(int len)
        {
            int[] data = null;
            switch (curMode)
            {
                case (byte)ChipMaximConstance.Reg.REG_MODE_RAWDATA_CRC:
                    data = ReadRawData(len);
                    break;

                case (byte)ChipMaximConstance.Reg.REG_MODE_ADC:
                    data = ReadAdc(len);
                    break;
            }

            return data;
        }

        /// <summary>
        /// 0x08:adc
        /// 美信测试版用 4Byte 传输
        /// </summary>
        /// <param name="len"></param>
        /// <returns></returns>
        private int[] ReadAdc(int cnt)
        {
            byte[] wBuf = new byte[256];
            byte[] rBuf = new byte[256];

            if (cnt % 2 != 0) return null;
            int len = (cnt - 2 - 2) / 4;

            wBuf[0] = I2CConstant.REG_IIC_ADDRESS;
            wBuf[1] = (byte)ChipMaximConstance.Reg.REG_DEBUG_DATA_A;
            uint rLen = (uint)(cnt);

            byte[] result;
            if (IIC.WriteRead(2, wBuf, rLen, rBuf))
            {
                if (CheckAndRemoveHeader(rBuf, cnt, out result))
                {
                    bool checkSum = Utils.CheckSum(rBuf, cnt);
                    short checksumValue = (short)((rBuf[cnt - 1] << 8 & 0xff00) | (rBuf[cnt - 2] & 0xff));

                    if (checkSum)
                    {
                        // data + checksum
                        int[] data = new int[len + 1];
                        byte[] temp = new byte[4];
                        for (int i = 0; i < len; i++)
                        {
                            data[i] = (int)(((result[i * 4 + 3] << 24) & 0xff000000)
                                | ((result[(i * 4) + 2] << 16) & 0xff0000)
                                | ((result[i * 4 + 1] << 8) & 0xff00)
                                | ((result[i * 4]) & 0xff));
                        }
                        data[len] = checksumValue;
                        //Console.WriteLine(string.Join(",", data));
                        return data;
                    }
                }
            }

            return null;
        }

        /// <summary>
        /// 0x10:rawdata
        /// 美信测试版用 2Byte 传输
        /// </summary>
        /// <param name="len"></param>
        /// <returns></returns>
        private int[] ReadRawData(int len)
        {
            byte[] wBuf = new byte[256];
            byte[] rBuf = new byte[256];

            if (len % 2 != 0)
            {
                return null;
            }

            wBuf[0] = I2CConstant.REG_IIC_ADDRESS;
            wBuf[1] = (byte)ChipMaximConstance.Reg.REG_DEBUG_DATA_A;

            if (IIC.WriteRead(2, wBuf, (uint)len, rBuf))
            {
                //ushort crcCheck1 = CRC_Check.calc_crc16(rBuf, (uint)(len - 2));
                //ushort crcCheck2 = CRC_Check.calc_crc16byte(rBuf, (uint)(len - 2));
                short crcCheck1 = (short)((rBuf[len - 1] << 8 & 0xff00) | (rBuf[len - 2] & 0xff));
                short crcCheck2 = (short)Utils.CalCRC16(Utils.GetAddress(rBuf), (uint)(len - 2));

                // Console.WriteLine(string.Format("crc1: {0}, crc2: {1}", crcCheck1, crcCheck2));

                if (crcCheck1 == crcCheck2)
                {
                    int[] data = new int[len / 2];
                    for (int i = 0; i < len / 2; i++)
                    {
                        data[i] = (short)(rBuf[i * 2 + 1] << 8 | rBuf[i * 2]);
                    }
                    return data;
                }
            }
            return null;
        }

        public string ReadFwVersion()
        {
            byte[] wBuf = new byte[256];
            byte[] rBuf = new byte[256];

            wBuf[0] = I2CConstant.REG_IIC_ADDRESS;
            wBuf[1] = (byte)ChipMaximConstance.Reg.REG_FW_VERSION;
            uint rLen = 2;
            uint wLen = 2;

            int cnt = 1;
            while (cnt <= REWRITE_TIMES)
            {
                if (IIC.WriteRead(wLen, wBuf, rLen, rBuf))
                {
                    return string.Format("v{0}.{1}",
                            rBuf[1].ToString(),
                            rBuf[0].ToString());
                }
                cnt++;
                Thread.Sleep(100);
            }

            return "-1, error";
        }

        public short ReadModuleConnect()
        {
            return 0xFF;
        }

        public string ReadModuleConnectDynamic()
        {
            return "11111111";
        }

        public byte[] ReadAfeGain()
        {
            return new byte[2];
        }

        public short[] ReadOffset(int chNum)
        {
            short[] offset = new short[chNum];
            return offset;
        }

        public short ReadDacToMvCoef()
        {
            return 0;
        }

        public int ReadAdcToUvCoef()
        {
            return 0;
        }

        public byte WriteCoeff(float[] coefficients)
        {
            return 0;
        }

        public float[] ReadCoeff(int chNum)
        {
            float[] coefs = new float[chNum];
            return coefs;
        }

        public static bool CheckAndRemoveHeader(byte[] source, int length, out byte[] result)
        {
            result = new byte[length];
            if (0x55 == source[0] && 0x44 == source[1])
            {
                for (int i = 2; i < length; i++)      // 跳过header，从第二项开始取数据
                {
                    result[i - 2] = source[i];
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public UpgradeResult UpdateFW(string filePath)
        {
            return new UpgradeResult();
        }
    }
}
